home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / prog_pas / ddplus63.zip / DOORTUT2.DOC < prev    next >
Text File  |  1991-10-10  |  18KB  |  464 lines

  1. ------------------------------------------------------------------------------
  2. Note: This article extracted from the September '91 issue of Carrier Detect
  3.       Journal. At this time, only part 1 of the series was available; Future
  4.       installments may be read in Carrier Detect Journal.
  5. ------------------------------------------------------------------------------
  6.  
  7.           *   Writing a BBS Door (Part 2)
  8.               Tutorial by Scott M. Baker
  9.  
  10.               I am happy to say that response to the first door
  11.           tutorial has been very encouraging. We've received several
  12.           requests for further continuation of the series, so here
  13.           is the second installment. For those joining us for the
  14.           first time, this series is about how to write a "door"
  15.           program. We're programming in Turbo Pascal and using my
  16.           DoorDriver kit for support. I encourage any of you who
  17.           have not yet read part I to review as it contains some
  18.           important introductory material.
  19.               Last time, I said we'd dig deeper into some
  20.           interactive communication with the user. The best way to
  21.           do this is with a sample program. Our last sample, HLODOOR
  22.           was pretty plain, so let's write something that is a bit
  23.           more exciting.
  24.               The following is NUMDOOR.PAS: a simple little game
  25.           designed to demonstrate some interactive communication
  26.           with the user.
  27.  
  28.           { 1} program numdoor;
  29.           { 2}
  30.           { 3} uses doordriv;
  31.           { 4}
  32.           { 5} procedure DoTheTitle;
  33.           { 6} begin;
  34.           { 7}  sclrscr;
  35.           { 8}  swriteln('Hello, '+user_first_name+
  36.           { 9}          ' '+user_last_name+
  37.           {10}          '. Welcome to NumDoor!');
  38.           {11}  swriteln('');
  39.           {12} end;
  40.           {13}
  41.           {14} procedure playgame;
  42.           {15} var
  43.           {16}  thenum: word;
  44.           {17}  playerguess: word;
  45.           {18}  guessnum: byte;
  46.           {19}  done: boolean;
  47.           {20}  tempstr: string;
  48.           {21} begin;
  49.           {22}  swriteln('I''m thinking of a number.'+
  50.           {23}           ' Can you guess what it is?');
  51.           {24}  swriteln('');
  52.           {25}  guessnum:=0;
  53.           {26}  randomize;
  54.           {27}  thenum:=random(100)+1;
  55.           {28}  done:=false;
  56.           {29}  while not done do begin;
  57.           {30}   inc(guessnum);
  58.           {31}   swrite('Guess #');
  59.           {32}   str(guessnum,tempstr);
  60.           {33}   swrite(tempstr);
  61.           {34}   swrite(': ');
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.           {35}   sread_num_word(playerguess);
  75.           {36}   if playerguess>thenum then swriteln('Lower!') else
  76.           {37}   if playerguess<thenum then swriteln('Higher!') else
  77.           {38}    if playerguess=thenum then begin;
  78.           {39}     swriteln('Correct!');
  79.           {40}     done:=true;
  80.           {41}    end;
  81.           {42}   if guessnum=10 then done:=true;
  82.           {43}  end; {while}
  83.           {44}  if thenum<>playerguess then begin;
  84.           {45}   swriteln('You Lost!');
  85.           {46}   str(thenum,tempstr);
  86.           {47}   swriteln('The number was '+tempstr+'.');
  87.           {48}  end;
  88.           {49} end;
  89.           {50}
  90.           {51} procedure waitforkey;
  91.           {52} var
  92.           {53}  ch: char;
  93.           {54} begin;
  94.           {55}  swriteln('');
  95.           {56}  swriteln('Press any key to continue.');
  96.           {57}  sread_char(ch);
  97.           {58} end;
  98.           {59}
  99.           {60} begin;
  100.           {61}  initdoordriver('DOORDRIV.CTL');
  101.           {62}  dothetitle;
  102.           {63}  playgame;
  103.           {64}  waitforkey
  104.           {65} end.
  105.  
  106.               Some of you were asking for a real door.. Well, there
  107.           it is. All 62 lines worth. Those of you using our new
  108.           LOCREAD program may wish to load up a second window on the
  109.           screen so you may view both the above source and the rest
  110.           of the article at the same time. On with the discussion...
  111.  
  112.               First lets look at an overview of the structure of
  113.           NUMDOOR. We've got three main procedures: DoTheTitle,
  114.           PlayGame, and WaitForKey. These procedures are pretty self
  115.           explanatory. DoTheTitle displays a little title
  116.           information about NUMDOOR. PlayGame performs the actual
  117.           task of playing the game, and WaitForKey waits for the
  118.           user to press a key once the game is over.
  119.  
  120.               Let's go through the program section by section. At
  121.           the very top, you'll notice lines one and three. Line 1
  122.           (Program NumDoor;) is simply us formally telling TP the
  123.           name of our program. Line 2 (Uses Doordriv;) is the
  124.           all-important "uses" statement which tells TP that we will
  125.           be using the DoorDriv TPU.
  126.  
  127.                              Procedure DoTheTitle
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.               The first procedure, DoTheTitle displays a little
  142.           introduction to the user so he knows where he is. Let's
  143.           look inside this procedure and see how it works:
  144.  
  145.               LINE 7: SCLRSCR;
  146.  
  147.               This is a DoorDriver procedure which we have not
  148.           introduced before. Sclrscr is DoorDriver's compliment to
  149.           the Turbo Pascal clrscr procedure. The clrscr procedure is
  150.           provided by TP to allow us to clear the screen. If you're
  151.           familiar with basic, then this is equivalent to a CLS.
  152.           Obviously, we will need to clear both the remote and the
  153.           local screens, so that's why we have to use DoorDriver's
  154.           Sclrscr.
  155.  
  156.               LINES 8-10: SWRITELN('Hello, '+user_first_name+ .....
  157.  
  158.               These lines display the introduction. As we learned in
  159.           part one of this tutorial, SWRITELN is DoorDriver's
  160.           compliment to Turbo Pascal's writeln procedure. You may
  161.           notice that I have separated the parameters across three
  162.           lines. This is perfectly legal - as long as the individual
  163.           components include plus (+) signs in between them, we can
  164.           split it up that way.
  165.               Another important note about this line: We include the
  166.           variables USER_FIRST_NAME and USER_LAST_NAME. These were
  167.           discussed in part one. For those who may have missed it,
  168.           DoorDriver places the user's first and last names into
  169.           those two respective variables. Sticking them in the
  170.           SWRITELN allows us to be a bit more personal to the user.
  171.  
  172.               LINE 11: SWRITELN('');
  173.  
  174.               You may be wondering, what is the point of writing
  175.           _nothing_ to the screen? The point is, like TP's writeln,
  176.           swriteln will output a CR/LF sequence. So even if we do
  177.           not write any data, the Carriage Return still goes out.
  178.           The effect is a blank line.
  179.  
  180.                               Procedure PlayGame
  181.  
  182.               PlayGame is where all of the real work takes place.
  183.           Let's take a minute to talk about what exactly the "game"
  184.           is that we are playing.
  185.               The game is a very common number guessing game. The
  186.           computer generates a random number and the user gets ten
  187.           shots to guess what it is. If the user guesses
  188.           incorrectly, the computer will tell whether he needs to go
  189.           "higher" or "lower". Now that we know what we want to do,
  190.           lets see how we would go about doing it. In pseudocode,
  191.           here's what we need to do:
  192.  
  193.               1) Generate a random number
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.               2) Ask the user for a guess
  207.               3) Compare the user's guess to our random number.
  208.               4) Say "lower", "higher", or "correct" based on the
  209.                  outcome of #3's comparison.
  210.               5) Loop back to 2 until either the user guesses the
  211.                  number correctly or uses up all ten tries.
  212.               6) If the user used up all ten tries, tell him he
  213.                  lost.
  214.  
  215.               That's our strategy. Now, let's go thought the actual
  216.           code.
  217.  
  218.               LINES 16-20: Variable Declarations
  219.  
  220.               We need a multitude of variables to store some of our
  221.           information in. THENUM is a word variable which will hold
  222.           the random number which we generate. PLAYERGUESS is
  223.           another word to hold the player's current guess. GUESSNUM
  224.           is a counter to hold how many times the user has guessed.
  225.           DONE is a boolean to tell us when we are done. And
  226.           finally, TEMPSTR is a temporary string which we will
  227.           discuss when we come to it.
  228.  
  229.               LINES 22-24: SWRITELN('I''m thinking of .....
  230.  
  231.               These lines comprise a little instruction that we give
  232.           the user. They're just simple swriteln statements, similar
  233.           to the ones we encountered in DoTheTitle.
  234.  
  235.               LINE 25: GUESSNUM:=0;
  236.  
  237.               Since Turbo Pascal does not initialize our variables,
  238.           we will have to do it ourselves. Guessnum is our counter
  239.           of how many guesses the user has made. Since he hasn't
  240.           made any yet, we've got to set it to zero.
  241.  
  242.               LINE 26: RANDOMIZE;
  243.  
  244.               The Randomize procedure is provided by Turbo Pascal to
  245.           randomize TP's random number generator. Without it, the
  246.           game would pick the same random number each time it runs.
  247.  
  248.               LINE 27: THENUM:=RANDOM(100)+1
  249.  
  250.               Here is where we get our random number. The random
  251.           function returns a number between zero and it's parameter
  252.           minus one. (i.e. Random(100) will include 0..99, not 100)
  253.           So we add 1 to it to get numbers between 1 and 100.
  254.  
  255.               LINE 28: DONE:=FALSE;
  256.  
  257.               Right now, we aren't done yet, (we haven't even hardly
  258.           started!) so we'd better set our variable accordingly.
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.               LINE 29: WHILE NOT DONE DO BEGIN;
  273.  
  274.               Line 29 sets up our "loop" which will ask the user for
  275.           up to ten guesses. We want to keep going as long as DONE
  276.           is not true. The loop consists of lines 29-43 which ask
  277.           the user for his guess and check it's validity.
  278.  
  279.               LINE 30: INC(GUESSNUM);
  280.  
  281.               We're on the first guess, so set guessnum accordingly.
  282.  
  283.               LINES 31-34: SWRITE('Guess #' .....
  284.  
  285.               These lines prompt the user for his guess. Although
  286.           they may seem complicated, they are really nothing more
  287.           than the simple SWRITE statements that we have seen
  288.           before. We just need to do some "magic" to manipulate our
  289.           data.
  290.               Let me explain our problem: SWRITE/SWRITELN only
  291.           accept string data. But, our variable GUESSNUM is a byte
  292.           variable which holds numeric information. So how do we get
  293.           this data into something we can use? The answer is that we
  294.           use Turbo Pascal's STR procedure. STR is a very handy
  295.           procedure which converts a numeric format variable to a
  296.           string format variable. So, when we say
  297.           STR(GUESSNUM,TEMPSTR), we are telling pascal to "take the
  298.           number in guessnum, convert it to a string, and place it
  299.           in tempstr".
  300.               Once this has been done, TEMPSTR now contains our
  301.           number which we can send out to swrite with no problem.
  302.  
  303.               LINE 35: SREAD_NUM_WORD(PLAYERGUESS);
  304.  
  305.               This line the major new concept that we are trying to
  306.           introduce. SREAD_NUM_WORD is a DoorDriver procedure which
  307.           will read a word variable from the user. It handles all
  308.           the details of waiting for the user to press keys,
  309.           converting the data to a word, etc and just gives us a
  310.           nice word variable.
  311.               This is where the "interaction" takes place. Until
  312.           now, we have just been displaying information to the user.
  313.           Now, we ask the user for some information back.
  314.           Specifically, we ask him for his guess. The guess is
  315.           stored in the variable PLAYERGUESS.
  316.  
  317.               LINES 36-41: If playerguess>thenum then ....
  318.  
  319.               This block comprises the code to test the player's
  320.           guess and act upon the results. We display "higher" or
  321.           "lower" if the number is higher or lower and if the user's
  322.           guess is correct, we display "correct" and set DONE to
  323.           true to end our loop.
  324.               This code is all standard pascal stuff (with some
  325.           swrites thrown) in so I won't go into too much detail
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.           here. We've got to try to stick to the doordriver-related
  339.           things or our little tutorial could get very big very
  340.           quickly.
  341.  
  342.               LINE 42: IF GUESSNUM=10 THEN DONE:=TRUE;
  343.  
  344.               If we're at the tenth guess, then it's time to end our
  345.           loop.
  346.  
  347.               LINES 44-48: IF PLAYERGUSS<>THENUM THEN BEGIN; ....
  348.  
  349.               We could have exited the loop for one of two reasons:
  350.           1) The user guessed correctly and DONE was set to true or
  351.           2) The user ran out of turns. These lines will check and
  352.           see if the user's guess was correct. If it was not, then
  353.           we got to break the bad news to him - he lost.
  354.               This code also includes our little trick of using STR
  355.           to convert the data. In this case, we have THENUM and we
  356.           need to convert it to a string so we can tell the user
  357.           what the number was. It works identically to the situation
  358.           we had in lines 31-34.
  359.  
  360.                              Procedure WaitForKey
  361.  
  362.               After we have finished PlayGame, we need to have a
  363.           little pause so the user gets to absorb the full impact of
  364.           his game playing. We could use a simple DELAY(2000) for a
  365.           20 second delay, but we are out to demonstrate interactive
  366.           communication, so let's wait for a keypress.
  367.               I'm not going into this line-by-line as it is such a
  368.           simple procedure. Rather, I'll describe what it does.
  369.           First, we tell the user we want him to hit a key with a
  370.           SWRITELN statement.
  371.               Then, we use DoorDriver's SREAD_CHAR procedure to read
  372.           a single character. SREAD_CHAR will wait for a key and
  373.           then return it to us. We used the variable CH to hold this
  374.           character.
  375.  
  376.                               The Main Procedure
  377.  
  378.               The main procedure, comprising lines 60-65 executes
  379.           all of our other procedure. Please note that similar to
  380.           HLODOOR, we had to call INITDOORDRIVER() to get DoorDriver
  381.           setup and ready for use.
  382.               After that, we just called DoTheTitle, PlayGame, and
  383.           WaitForKey in order. Then, we exit.
  384.  
  385.                              Interactive Routines
  386.  
  387.               We have introduced two new very important routines:
  388.           SREAD_NUM_WORD and SREAD_CHAR. DoorDriver includes a whole
  389.           set of similar routines for doing similar things. Here's a
  390.           listing of them:
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.               SREAD(s: string);              Reads in a string
  405.  
  406.               SREAD_NUM(i: integer);         Reads in an integer
  407.  
  408.               SREAD_NUM_WORD(w: word);       Reads in a word
  409.  
  410.               SREAD_NUM_LONGINT(l: longint); Reads in a longint
  411.  
  412.               SREAD_CHAR(CH: CHAR);          Reads in a char
  413.  
  414.               The first four of these routines will read in data
  415.           until the user presses the return key. For example
  416.           "1234"<return>. They allow the user to backspace back and
  417.           forth to correct his mistakes. These are very similar to
  418.           Turbo Pascal's READLN and Basic's INPUT statements.
  419.               The fifth procedure (SREAD_CHAR) will wait for a
  420.           character and return that character. It's simply for when
  421.           you want one character and only one character. The user
  422.           can't correct his mistakes with backspace or anything.
  423.           This routine also does not echo to the screen.
  424.               SREAD_CHAR performs almost identically to Turbo
  425.           Pascal's READKEY function. In Turbo Pascal you would use
  426.           ch:=READKEY; With DoorDriver, use SREAD_CHAR(CH).
  427.  
  428.                                   Conclusion
  429.  
  430.               This installment has turned out a lot longer than I
  431.           had anticipated. However, we have gained some very
  432.           important knowledge. We now know how to ask the user for
  433.           data.
  434.               If you like, play with DD's other input routines
  435.           (SREAD,SREAD_NUM, etc) and see what you can do with them.
  436.           They are very important to the operation of a door.
  437.               You might also want to try altering the look and feel
  438.           of NUMDOOR. You can expand the SWRITELN statements to
  439.           provide a more impressive instruction and title section.
  440.           Or if you are feeling really adventurous, you may want to
  441.           look in the DoorDriver manual and peek into the
  442.           SET_FOREGROUND procedure which will let you set the color
  443.           of the text. That is one of the key things we will
  444.           introduce next time.
  445.               Please, if you have any questions or suggestions, you
  446.           can either send them directly or to Michael Crosson,
  447.           editor and published of Carrier Detect. I am right now
  448.           still deciding in which direction to take this series -
  449.           should we work on creating one large program? Or introduce
  450.           features with a lot more small programs such as NUMDOOR
  451.           and HLODOOR. You tell me!
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.